package com.clp.inflxudb.spring;

import com.clp.inflxudb.anno.FMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.filter.AnnotationTypeFilter;

import java.util.Set;

class FluxClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
    private static Logger LOGGER = LoggerFactory.getLogger(FluxClassPathBeanDefinitionScanner.class);

    public FluxClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> holders = super.doScan(basePackages);
        if (holders.isEmpty()) {
            LOGGER.warn("在{}包中未扫描到任何Flux的Mapper！");
        }
        processBeanDefinitions(holders);
        return holders;
    }

    @Override
    protected void registerDefaultFilters() {
        // if specified, use the given annotation and / or marker interface
        addIncludeFilter(new AnnotationTypeFilter(FMapper.class,true,true));

        // exclude package-info.java
        addExcludeFilter((metadataReader, metadataReaderFactory) -> {
            String className = metadataReader.getClassMetadata().getClassName();
            return className.endsWith("package-info");
        });
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
    }

    private void processBeanDefinitions(Set<BeanDefinitionHolder> holders) {
        AbstractBeanDefinition definition;
        BeanDefinitionRegistry registry = getRegistry();

        //遍历处理每一个 mapper beanDefinition
        for (BeanDefinitionHolder holder : holders) {
            definition = (AbstractBeanDefinition) holder.getBeanDefinition();
            String beanClassName = definition.getBeanClassName();

            // mapper 的接口是mapper类本身的类型，但是在 beanDefinition 中，它的实际 beanClass 是一个 FactoryBean。之后再获取 mapper 实例的时候，都是通过 FactoryBean 的 getObject 方法来获取的
            // 如：beanClassName：com.baowen.springdetail.mapper.UserMapper，mapperFactoryBeanClass：org.mybatis.spring.mapper.MapperFactoryBean
            definition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName); // issue #59
            definition.setBeanClass(FluxMapperFactoryBean.class);
        }
    }
}
